using System;
using System.Collections.Generic;
using System.Linq;
using Generator.Model;
using Namespace = Generator.Model.Namespace;

namespace Generator.Renderer.Internal;

internal static class FrameworkTypeRegistration
{
    public static string Render(GirModel.Namespace ns)
    {
        return $@"
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using GObject;
using GObject.Internal;

namespace {Namespace.GetInternalName(ns)};

// AUTOGENERATED FILE - DO NOT MODIFY

internal class TypeRegistration
{{
    internal static void RegisterTypes()
    {{
        {ns.Classes
            .Where(cls => !cls.Fundamental)
            .Select(RenderRegistration)
            .Join(Environment.NewLine)}

        {ns.Interfaces
            .Select(RenderInterfaceRegistration)
            .Join(Environment.NewLine)}

        {ns.Records
            .Where(record => record.TypeFunction is not null)
            .Select(RenderRegistration)
            .Join(Environment.NewLine)}

        {ns.Unions
            .Where(union => union.TypeFunction is not null)
            .Select(RenderRegistration)
            .Join(Environment.NewLine)}
    }}

    private static void Register<T>(params OSPlatform[] supportedPlatforms) where T : InstanceFactory, GTypeProvider
    {{
         try
         {{
            if(supportedPlatforms.Any(RuntimeInformation.IsOSPlatform))
                GObject.Internal.DynamicInstanceFactory.Register(T.GetGType(), T.Create);
         }}
         catch(System.Exception e)
         {{
             Debug.WriteLine($""Could not register type: {{e.Message}}"");
         }}
     }}
}}";
    }

    private static string RenderRegistration(GirModel.ComplexType type)
    {
        return $"Register<{ComplexType.GetFullyQualified(type)}>({RenderPlatforms(type as GirModel.PlatformDependent)});";
    }

    private static string RenderInterfaceRegistration(GirModel.Interface type)
    {
        return $"Register<{Interface.GetFullyQualifiedImplementationName(type)}>({RenderPlatforms(type as GirModel.PlatformDependent)});";
    }

    private static string RenderPlatforms(GirModel.PlatformDependent? platformDependent)
    {
        if (platformDependent is null)
            return string.Empty;

        var statements = new List<string>();

        if (platformDependent.SupportsLinux)
            statements.Add("OSPlatform.Linux");

        if (platformDependent.SupportsMacos)
            statements.Add("OSPlatform.OSX");

        if (platformDependent.SupportsWindows)
            statements.Add("OSPlatform.Windows");

        return string.Join(", ", statements);
    }
}
